﻿Imports SFDL.LoaderExtensions
Imports SFDL.Logging
Imports Microsoft.WindowsAPICodePack.Taskbar
Imports SFDL.Core
Imports System.Threading
Imports System.Threading.Tasks
Imports SFDL.Loader.My.Resources

Module DownloadProgressHelper

    Friend _var_remaining_time As String = String.Empty
    Friend _var_download_speed As String = String.Empty
    Friend _var_download_progress As String = String.Empty

    Private _var_item_speed_size_collection As New Dictionary(Of String, OLV_Item)
    Private _obj_lock_SizeSpeedCollection As New Object
    Private _obj_lock_update_tss As New Object
    Private _log As NLog.Logger = NLog.LogManager.GetLogger("DownloadProgressHelper")

    Sub ClearSizeSpeedCollection()

        Try

            Monitor.Enter(_obj_lock_SizeSpeedCollection)

            _var_item_speed_size_collection.Clear()

        Catch ex As Exception

        Finally
            Monitor.Exit(_obj_lock_SizeSpeedCollection)
        End Try

    End Sub

    Sub UpdateItemSizeSpeedCollection(ByVal _olv_item As OLV_Item)

        Try

            Monitor.Enter(_obj_lock_SizeSpeedCollection)

            If _var_item_speed_size_collection.ContainsKey(_olv_item.FileName) Then
                _var_item_speed_size_collection.Remove(_olv_item.FileName)
            End If

            _var_item_speed_size_collection.Add(_olv_item.FileName, _olv_item)

        Catch ex As Exception
            _log.Error(ex, "Fehler beim updaten der SizeSpeedCollection!")
        Finally
            Monitor.Exit(_obj_lock_SizeSpeedCollection)
        End Try

    End Sub

    Sub RemoveItemFromSizeSpeedCollection(ByVal _olv_item As OLV_Item)

        Try

            Monitor.Enter(_obj_lock_SizeSpeedCollection)

            If _var_item_speed_size_collection.ContainsKey(_olv_item.FileName) Then
                _var_item_speed_size_collection.Remove(_olv_item.FileName)
            End If

        Catch ex As Exception
            _log.Error(ex, ex.Message)
        Finally
            Monitor.Exit(_obj_lock_SizeSpeedCollection)
        End Try

    End Sub

    Sub UpdateItem(_item As OLV_Item, _event_type As UpdateItemEventType)

        Task.Factory.StartNew(Sub()

                                  Try

                                      Select Case _event_type

                                          Case UpdateItemEventType.NotEnoughDiskSpace

                                              _item.Status = Status.Failure
                                              _item.StatusText = StringMessages.OLVItemStatusNotEnoughDiskSpace
                                              _item.Progress = 0
                                              _item.DownloadSpeed = String.Empty

                                          Case UpdateItemEventType.FileNameTooLong

                                              _item.Status = Status.Failure
                                              _item.StatusText = StringMessages.OLVItemStatusFileNameTooLong
                                              _item.Progress = 0
                                              _item.DownloadSpeed = String.Empty

                                          Case UpdateItemEventType.DirectoryNotFound

                                              _item.Status = Status.Failure
                                              _item.StatusText = StringMessages.OLVItemStatusDirectoryNotFound
                                              _item.Progress = 0
                                              _item.DownloadSpeed = String.Empty

                                          Case UpdateItemEventType.FileNotFound

                                              _item.Status = Status.Failure
                                              _item.StatusText = StringMessages.OLVItemStatusFileNotFound
                                              _item.Progress = 0
                                              _item.DownloadSpeed = String.Empty

                                          Case UpdateItemEventType.ConnectionError

                                              _item.Status = Status.Failure
                                              _item.StatusText = StringMessages.OLVItemStatusConnectionError
                                              _item.Progress = 0
                                              _item.DownloadSpeed = String.Empty

                                          Case UpdateItemEventType.AuthError

                                              _item.Status = Status.Failure
                                              _item.StatusText = StringMessages.OLVItemStatusAuthError
                                              _item.Progress = 0
                                              _item.DownloadSpeed = String.Empty

                                          Case UpdateItemEventType.ServerDown

                                              _item.Status = Status.Failure
                                              _item.StatusText = StringMessages.OLVItemStatusServerDown
                                              _item.Progress = 0
                                              _item.DownloadSpeed = String.Empty

                                          Case UpdateItemEventType.ServerFull

                                              _item.Status = Status.Failure
                                              _item.StatusText = StringMessages.OLVItemStatusServerFull
                                              _item.Progress = 0
                                              _item.DownloadSpeed = String.Empty

                                          Case UpdateItemEventType.InternalServerError

                                              _item.Status = Status.Failure
                                              _item.StatusText = StringMessages.OLVItemStatusInternalServerError
                                              _item.Progress = 0
                                              _item.DownloadSpeed = String.Empty

                                          Case UpdateItemEventType.UnknownError

                                              _item.Status = Status.Failure
                                              _item.StatusText = StringMessages.OLVItemStatusUnknownError
                                              _item.Progress = 0
                                              _item.DownloadSpeed = String.Empty

                                          Case UpdateItemEventType.Retry

                                              _item.Status = Status.Retry
                                              _item.StatusText = StringMessages.OLVItemStatusRetry
                                              _item.DownloadSpeed = String.Empty

                                          Case UpdateItemEventType.DownloadRunning

                                              _item.Status = Status.Running
                                              _item.StatusText = StringMessages.OLVItemStatusDownloadRunning

                                          Case UpdateItemEventType.DownloadComplete

                                              _item.Status = Status.Complete
                                              _item.StatusText = StringMessages.OLVItemStatusDownloadComplete
                                              _item.DownloadSpeed = String.Empty
                                              _item.Progress = 100

                                          Case UpdateItemEventType.DownloadComplete_HashValid

                                              _item.Status = Status.CompleteHashValid
                                              _item.StatusText = StringMessages.OLVItemStatusDownloadComplete_HashValid
                                              _item.DownloadSpeed = String.Empty
                                              _item.Progress = 100

                                          Case UpdateItemEventType.DownloadComplete_HashInvalid

                                              _item.Status = Status.CompleteHashInvalid
                                              _item.StatusText = StringMessages.OLVItemStatusDownloadComplete_HashInvalid
                                              _item.DownloadSpeed = String.Empty
                                              _item.Progress = 100

                                          Case UpdateItemEventType.FileValdilation

                                              _item.Status = Status.FileValdilation
                                              _item.StatusText = StringMessages.OLVItemStatusFileValdilation
                                              _item.DownloadSpeed = String.Empty

                                          Case UpdateItemEventType.DownloadStopped

                                              _item.Status = Status.Stopped
                                              _item.StatusText = StringMessages.OLVItemStatusStopped
                                              _item.DownloadSpeed = String.Empty

                                          Case UpdateItemEventType.FileAlreadyDownloaded

                                              _item.Status = Status.AlreadyDownloaded
                                              _item.StatusText = StringMessages.OLVItemStatusFileAlreadyDownloaded
                                              _item.DownloadSpeed = String.Empty
                                              _item.Progress = 100
                                              _item.Checked = False

                                      End Select

                                      frm_main.OLV_Download_Items.RefreshObject(_item)


                                  Catch ex As Exception
                                      _log.Error(ex, "Konnte Item nicht updaten!")
                                  End Try

                              End Sub, New CancellationToken, TaskCreationOptions.PreferFairness, GetRootUIContext).ContinueWith(Sub()

                                                                                                                                     UpdateItemSizeSpeedCollection(_item)

                                                                                                                                     UpdateSpeedAndRemaingTime()

                                                                                                                                 End Sub, New CancellationToken, TaskContinuationOptions.PreferFairness)

    End Sub

    Sub UpdateItemProgress(_item As OLV_Item, _session_name As String, _download_speed As String, _precent_downloaded As Integer)

        Task.Factory.StartNew(Sub()

                                  _item.Status = Status.Running
                                  _item.StatusText = StringMessages.OLVItemStatusDownloadRunning
                                  _item.Progress = _precent_downloaded
                                  _item.DownloadSpeed = _download_speed

                                  UpdateItemSizeSpeedCollection(_item)

                                  UpdateSpeedAndRemaingTime()

                              End Sub, New CancellationToken, TaskCreationOptions.PreferFairness).ContinueWith(Sub()
                                                                                                                       frm_main.OLV_Download_Items.RefreshObject(_item)
                                                                                                               End Sub, New CancellationToken, TaskContinuationOptions.PreferFairness, GetRootUIContext)

    End Sub

    Sub UpdateSpeedAndRemaingTime()

        Dim _tools As New Tools

        Dim _total_speed As Double
        Dim _total_size As Double
        Dim _total_size_downloaded As Double
        Dim _size_remaining As Double
        Dim _time_remaining As Double

        If GetDownloadStopInProgress = False And GetDownloadRunning = True Then

            Try

                Task.Factory.StartNew(Sub()

                                          Try

                                              Monitor.Enter(_obj_lock_SizeSpeedCollection)

                                              _total_speed = 0
                                              _total_size = 0
                                              _total_size_downloaded = 0
                                              _size_remaining = 0
                                              _time_remaining = 0


                                              For Each _item In _var_item_speed_size_collection

                                                  Dim _raw_speed As String = String.Empty

                                                  If _item.Value.Checked = True Then

                                                      _total_size += _item.Value.FileSize
                                                      _total_size_downloaded += _item.Value.SizeDownloaded


                                                      If Not String.IsNullOrEmpty(_item.Value.DownloadSpeed) Then

                                                          If _item.Value.DownloadSpeed.ToString.Contains("KB/s") Then
                                                              _raw_speed = _item.Value.DownloadSpeed.ToString.Replace("KB/s", "").Trim
                                                              _total_speed += Double.Parse(_raw_speed)
                                                          End If

                                                          If _item.Value.DownloadSpeed.ToString.Contains("MB/s") Then
                                                              _raw_speed = _item.Value.DownloadSpeed.ToString.Replace("MB/s", "").Trim
                                                              _total_speed += Double.Parse(_raw_speed) * 1024
                                                          End If

                                                      End If

                                                  End If

                                              Next


                                          Catch ex As Exception
                                              _log.Error(ex, "Fehler beim berechnen des Downloadspeeds und der verbleibenden Zeit!")
                                          Finally
                                              Monitor.Exit(_obj_lock_SizeSpeedCollection)
                                          End Try

                                      End Sub).ContinueWith(Sub()

                                                                Try

                                                                    _size_remaining = _total_size - _total_size_downloaded

                                                                    _time_remaining = Math.Round(Double.Parse(CStr(((_size_remaining / 1024) / _total_speed) / 60)), 2)

                                                                    _var_remaining_time = String.Format(StringMessages.StatusStripMessageETA, _tools.ConvertDecimal2Time(_time_remaining).ToString)

                                                                    If _total_speed >= 1024 Then
                                                                        _var_download_speed = String.Format("Speed: {0} MB/s", Math.Round(_total_speed / 1024, 2))
                                                                    Else
                                                                        _var_download_speed = String.Format("Speed: {0} KB/s", _total_speed)
                                                                    End If

                                                                    _var_download_progress = CInt((_total_size_downloaded / _total_size) * 100).ToString & "%"

                                                                Catch ex As Exception
                                                                    _log.Error(ex, ex.Message)
                                                                End Try


                                                            End Sub, New CancellationToken, TaskContinuationOptions.NotOnFaulted).ContinueWith(Sub()

                                                                                                                                                   SyncLock _obj_lock_update_tss

                                                                                                                                                       Try

                                                                                                                                                           frm_main.tss_time_remaining.Text = _var_remaining_time
                                                                                                                                                           frm_main.tss_currentspeed.Text = _var_download_speed
                                                                                                                                                           frm_main.tss_progressbar.Value = CInt((_total_size_downloaded / _total_size) * 100)

                                                                                                                                                           'Taskbar
                                                                                                                                                           If TaskbarManager.IsPlatformSupported Then
                                                                                                                                                               frm_main.GetTaskbarManager.SetProgressValue(CInt((_total_size_downloaded / _total_size) * 100), 100)
                                                                                                                                                           End If

                                                                                                                                                       Catch ex As Exception
                                                                                                                                                           _log.Error(ex, ex.Message)
                                                                                                                                                       End Try

                                                                                                                                                   End SyncLock

                                                                                                                                               End Sub, New CancellationToken, TaskContinuationOptions.None, _ui_context)

            Catch ex As Exception
                _log.Error(ex, ex.Message)
            End Try

        End If

    End Sub

End Module